package com.syl.springcloud.tempadmin.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import static java.util.Locale.ENGLISH;

/**
 * 反射基础工具类
 *
 * @author syl
 * @create 2018-06-17 0:53
 **/
public class ReflectUtil {
    private static final Logger LOG = LoggerFactory.getLogger(ReflectUtil.class);

    private static List<String> BASE_DATA_TYPE = new ArrayList<>();
    static {
        BASE_DATA_TYPE.add("byte");
        BASE_DATA_TYPE.add("short");
        BASE_DATA_TYPE.add("int");
        BASE_DATA_TYPE.add("long");
        BASE_DATA_TYPE.add("float");
        BASE_DATA_TYPE.add("double");
        BASE_DATA_TYPE.add("boolean");
        BASE_DATA_TYPE.add("char");
    }

//    private static Object methodInvokeHelp(Object instance, String methodName, Class[] parameterTypes,Object[] param){
//        try {
//            Method method = instance.getClass().getMethod(methodName, parameterTypes);
//            return (List<Schema>) method.invoke(instance, param);
//        } catch (NoSuchMethodException e) {
//            LOG.error("反射method 方法异常",e);
//        }catch (IllegalAccessException e) {
//            e.printStackTrace();
//        } catch (InvocationTargetException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

    /**
     * 给普通 java bean 对象字段赋值 (不能作用于链式bean 不能作用于枚举)
     * @param entity
     * @param field
     * @param fieldValue
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setFieldValue(Object entity,String field,Object... fieldValue) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        PropertyDescriptor pd = new PropertyDescriptor(field,entity.getClass());
        pd.getWriteMethod().invoke(entity, fieldValue);
    }

    /**
     * 获取普通java bean 对象字段 (不能作用于链式bean 不能作用于枚举)
     * @param entity
     * @param field
     * @return
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object getFieldValue(Object entity,String field) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        PropertyDescriptor pd = new PropertyDescriptor(field,entity.getClass());
        Method method = pd.getReadMethod();
        return method.invoke(entity);
    }

    /**
     * 通用给 java bean 对象字段赋值 请确保参数为包装类,无法设置参数类型为普通基础数据类型
     * @param entity 实例对象
     * @param prefix 方法名前缀
     * @param field 字段
     * @param fieldValue 字段值
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setFieldValue(Object entity,String prefix,String field,Object... fieldValue) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        field = field.trim();
        if(field == null || field.isEmpty())return;
        String baseName = field.substring(0, 1).toUpperCase(ENGLISH) + field.substring(1);
        String prefixTemp = prefix == null || prefix.isEmpty() ? "set" : prefix;
        String readMethodName = prefixTemp + baseName;
        Class[] temp = new Class[fieldValue.length];
        for (int i = 0; i < fieldValue.length; i++) {
            Class cz = fieldValue[i].getClass();
            temp[i] = cz;
        }
        Method method = entity.getClass().getMethod(readMethodName, temp);
        method.invoke(entity,fieldValue);
    }

    /**
     * 通用获取普通java bean 对象字段
     * @param entity
     * @param field
     * @param cz 不能为基础数据类型
     * @param <T>
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static <T> T getFieldValue(Object entity,String field,Class<T> cz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        String typeName = cz.getTypeName();
        if(BASE_DATA_TYPE.contains(typeName)){
            throw new RuntimeException("无法转换基本数据类型, 请使用包装类");
        }
        field = field.trim();
        if(field == null || field.isEmpty())return null;
        String baseName = field.substring(0, 1).toUpperCase(ENGLISH) + field.substring(1);
        String readMethodName;
        if (cz == boolean.class) {
            readMethodName = "is" + baseName;
        } else {
            readMethodName = "get" + baseName;
        }
        Method method = entity.getClass().getMethod(readMethodName);
        Object invoke = method.invoke(entity);
        if("java.lang.String".equals(typeName)){
            return cz.cast(invoke.toString());
        }
        return cz.cast(invoke);
    }

}
